home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-05 / pcb121.zip / 3C507.INC next >
Text File  |  1992-01-23  |  40KB  |  1,133 lines

  1. ;;******************************************************************************
  2. ;;                         3c507.inc      3c507.inc
  3. ;;******************************************************************************
  4. ;;
  5. ;;  Copyright (C) 1991 Vance Morrison
  6. ;;
  7. ;;
  8. ;; Permission to view, compile, and modify for LOCAL (intra-organization) 
  9. ;; USE ONLY is hereby granted, provided that this copyright and permission 
  10. ;; notice appear on all copies.  Any other use by permission only.
  11. ;;
  12. ;; Vance Morrison makes no representations about the suitability 
  13. ;; of this software for any purpose.  It is provided "as is" without expressed 
  14. ;; or implied warranty.  See the copywrite notice file for complete details.
  15. ;;
  16. ;;******************************************************************************
  17. ;; 3c507.inc holds the interface routines for the 3com etherlink 16 card.
  18. ;;
  19. ;; The functions provided by this file are
  20. ;;
  21. ;;   C507_DECLARE name, io_address, seg, len, promiscuous
  22. ;;   C507_DEFINE_out_AX name, fail
  23. ;;   C507_IF_R_ACCESS_out_BX_CX_ES name, no_packet
  24. ;;   C507_IF_R_CONT_in_BX_CX_ES_const_BX_CX_DX_BP_SI_DI_ES name, ok
  25. ;;   C507_IF_R_FREE_const_BX_CX_BP_SI_DI_ES name
  26. ;;   C507_IF_W_ACCESS_in_CX_out_DI_ES_const_BX_CX_BP name, no_buffer
  27. ;;   C507_IF_W_WRITE_in_CX_const_BX_BP_ES name
  28. ;;   C507_IF_SET_ADDRESS_in_SI_const_BX_CX_BP_DI_ES name
  29. ;;   C507_IF_COPY_in_CX_SI_DI_ES_out_SI_DI_const_BX_BP_ES name
  30. ;;
  31. ;; Variables set by this module
  32. ;;
  33. ;;   c507_&name&_declared                     ;; one if this interface exists
  34. ;;   if_&name&_address                       ;; the hardware address
  35. ;;   if_&name&_mtu                           ;; the maximum trans unit
  36. ;;
  37. ;;******************************************************************************
  38. ;; data storage needed by this module
  39.  
  40. c507_data  STRUC
  41. ;; these values are set at init only
  42.     c507_base             dw 0  ;; the offset value for shared memory
  43.     c507_end_buff         dw 0    ;; end of buffer block for packet data
  44.     c507_start_buff       dw 0    ;; begining of buffer block for packet data
  45.  
  46.     ;; set at init, and updated at FREE
  47.     c507_last_rbd         dw 0  ;; points to buff desc with the EOL marker
  48.     c507_last_rfd         dw 0  ;; points to frame desc with the EOL marker
  49.  
  50.     ;; set at R_ACCESS used at FREE
  51.     c507_last_frame_rbd   dw 0  ;; last buff descriptor in current frame
  52.     c507_cur_frame        dw 0    ;; pointer to current frame
  53.  
  54.     c507_cur_tcb          dw 0  ;; current transmit command buffer
  55. c507_data ENDS
  56.  
  57.  
  58. ;;******************************************************************************
  59. ;;   C507_DECLARE name, io_address, seg, len, promiscuous
  60. ;; declares that there is a 3c507 ethernet card at 'io_address'.  The
  61. ;; shared memory starts a the SEGMENT 'seg' and has length 'len'.  
  62. ;; if 'promiscuous' is non-blank and non-zero then every packet on
  63. ;; the ethernet is returned.
  64. ;;
  65. c507_first = 0          ;; the first 3c507 card.  
  66.  
  67. C507_DECLARE MACRO name, io_address, seg, len, promiscuous
  68.     .errb <seg>
  69.     .errb <len>
  70.  
  71.     .DATA
  72.     c507_&name&_declared     = 1
  73.     c507_&name&_io           = io_address
  74.     c507_&name&_seg          = seg
  75.     c507_&name&_len          = len
  76.  
  77.     c507_&name&_promiscuous = 0
  78.     ifnb <promiscuous>
  79.         c507_&name&_promiscuous = 0&promiscuous
  80.     endif
  81.  
  82.     if (name le c507_first) or (c507_first eq 0)
  83.         c507_first = name
  84.     endif
  85.  
  86.     if_&name&_mtu = 1514
  87.  
  88.     global c507_&name&_data:c507_data
  89.     global if_&name&_address:word 
  90.  
  91.     .CODE
  92.     global c507_&name&_real_define:near
  93. ENDM
  94.  
  95.  
  96. ;;******************************************************************************
  97. ;;   IF_DEFINE name
  98. ;;      sets asside memory an name object and initializes it.  This
  99. ;;      routine is a no-op if 'name' was not declared
  100. ;;      Note that if multiple 3C507 cards are present, they must be
  101. ;;      the smallest named card must be defined first (since this card
  102. ;;      turns on all the cards).  AX holds a failure code if the initialization
  103. ;;      fails.
  104. ;;
  105. C507_DEFINE_out_AX MACRO name, fail
  106. ifdef c507_&name&_declared
  107.     call c507_&name&_real_define
  108.     or AX, AX
  109.     jnz fail
  110. endif
  111. ENDM
  112.  
  113. C507_REAL_DEFINE MACRO name
  114.     local ret_code, rfd_loop, found_rfd, rbd_loop, found_rbd
  115.     .errb <name>
  116.  
  117. ifdef c507_&name&_declared
  118.     .DATA
  119.     if_&name&_address DW 3 dup (0)
  120.     c507_&name&_data  c507_data <>
  121.  
  122.     .CODE
  123. c507_&name&_real_define:
  124.  
  125.         ;; put all card in run state (only done for first card)
  126.     if name eq c507_first
  127.         xor AX, AX
  128.         WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES C507_ID_PORT, 0
  129.         C507_SEND_ID_const_BX_BP_SI_DI_ES C507_ID_PORT 
  130.         xor AX, AX
  131.         WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES C507_ID_PORT, 0
  132.     endif
  133.  
  134.         ;; get the ethernet address
  135.     mov SI, offset if_&name&_address
  136.     C507_GET_ADDRESS_in_SI_const_BX_BP_DI_ES c507_&name&_io
  137.  
  138.     C507_INIT_SETUP_out_ES c507_&name&_io, c507_&name&_seg, c507_&name&_len, if_&name&_address, c507_&name&_promiscuous, ret_code
  139.     mov c507_&name&_data.c507_base, ES
  140.  
  141.         ;; initialize my state variables
  142.     mov SI, ES:[SCB+scb_rframes]
  143.     mov c507_&name&_data.c507_cur_frame, SI
  144.  
  145.     mov DI, ES:[SI+rfd_rbd]     ;; DI points to the first buffer descriptor, we
  146.                                 ;; assume that this rbd points to the begining
  147.                                 ;; of the large block of memory
  148.     mov DX, ES:[DI+rbd_buff.offs]
  149.     mov c507_&name&_data.c507_start_buff, DX
  150.  
  151.         ;; find the last element of the Buffer list
  152.     rbd_loop:
  153.         test ES:[DI+rbd_len], RBD_LEN_EOL
  154.         jnz found_rbd
  155.         mov DI, ES:[DI+rbd_next]
  156.     jmp rbd_loop
  157.     found_rbd:
  158.     mov c507_&name&_data.c507_last_rbd, DI
  159.  
  160.     mov AX, ES:[DI+rbd_len] ;; DI points to the last buffer descriptor.  we
  161.                             ;; assume that this rbd points to the end of the
  162.                             ;; large block of memory.
  163.     and AX, RBD_LEN_MSK
  164.     mov DX, ES:[DI+rbd_buff.offs]
  165.     add DX, AX
  166.     mov c507_&name&_data.c507_end_buff, DX
  167.  
  168.         ;; find the last element of the Frame list
  169.     mov DI, ES:[SCB+scb_rframes]
  170.     rfd_loop:
  171.         test ES:[DI+rfd_cmd], RFD_CMD_EOL
  172.         jnz found_rfd
  173.         mov DI, ES:[DI+rfd_next]
  174.     jmp rfd_loop
  175.     found_rfd:
  176.     mov c507_&name&_data.c507_last_rfd, DI
  177.  
  178.     mov c507_&name&_data.c507_cur_tcb, CU_TCMD1
  179.  
  180.     xor AX, AX
  181. ret_code:
  182.    ret
  183.  
  184. endif
  185. ENDM
  186.  
  187.  
  188. ;;******************************************************************************
  189. ;;   IF_R_ACCESS_out_BX_ES name, no_packet
  190. ;;       IF_R_ACCESS waits for the next packet to come from the the board
  191. ;;       associated with 'name' and returns a pointer to the begining of 
  192. ;;       an ethernet packet in BX:ES.  CX holds the length of the packet
  193. ;;       R_ACCESS jumps to 'no_packet' if there are no packets waiting to 
  194. ;;       be read in
  195. ;;       
  196. C507_IF_R_ACCESS_out_BX_CX_ES MACRO name, no_packet
  197.     local look_packet, found_packet, len_loop, last_buff
  198.     .errb <no_packet>
  199.  
  200.     mov ES, c507_&name&_data.c507_base
  201.     mov SI, c507_&name&_data.c507_cur_frame
  202.  
  203.  
  204.     look_packet:
  205.         mov AX, ES:[SI+rfd_status]
  206.         test AX, RFD_STAT_DONE
  207.         jz no_packet
  208.  
  209.         test AX, RFD_STAT_OK
  210.         jnz found_packet
  211.         mov SI, ES:[SI+rfd_next]
  212.     jmp look_packet                     
  213.     found_packet:
  214.  
  215.     mov c507_&name&_data.c507_cur_frame, SI
  216.     mov SI, ES:[SI+rfd_rbd]
  217.     mov BX, ES:[SI+rbd_buff.offs]
  218.  
  219.         ;; compute the length of the packet, as well as if it wrapped or not
  220.     xor CX, CX
  221.     len_loop:
  222.         mov AX, ES:[SI+rbd_used_len]
  223.         test AX, RBD_USED_LEN_EOF
  224.         jnz last_buff
  225.         and AX, RBD_USED_LEN_MSK
  226.         add CX, AX
  227.         mov SI, ES:[SI+rbd_next]
  228.     jmp len_loop
  229.     last_buff:
  230.     and AX, RBD_USED_LEN_MSK
  231.     add CX, AX
  232.     mov c507_&name&_data.c507_last_frame_rbd, SI
  233. ENDM
  234.  
  235.  
  236. ;;******************************************************************************
  237. ;;   IF_R_FREE_const_BX_CX_BP_SI_DI_ES  name
  238. ;;       After the client is through processing the packet returned by 
  239. ;;       IF_R_ACCESS, IF_R_FREE must be called to inform 'name' that the 
  240. ;;       memory that the packet was in can be reused for future packets.
  241. ;;
  242. C507_IF_R_FREE_const_BX_CX_BP_SI_DI_ES MACRO name
  243.     local ok_rbd, do_restart, no_restart, look_first_ndone, found_restart
  244.     .errb <name>
  245.  
  246.     mov DX, SI                                  ;; save SI
  247.     mov AX, ES
  248.     xchg AX, c507_&name&_data.c507_base         ;; load/save ES
  249.     mov ES, AX
  250.  
  251.     mov SI, c507_&name&_data.c507_last_frame_rbd
  252.     or ES:[SI+rbd_len], RBD_LEN_EOL
  253.  
  254.     mov SI, c507_&name&_data.c507_last_rbd
  255.     and ES:[SI+rbd_len], (NOT RBD_LEN_EOL)
  256.  
  257.     mov SI, c507_&name&_data.c507_last_frame_rbd
  258.     mov c507_&name&_data.c507_last_rbd, SI
  259.  
  260.     mov SI, c507_&name&_data.c507_cur_frame
  261.     mov AX, SI
  262.     mov ES:[SI+rfd_status], 0
  263.     or ES:[SI+rfd_cmd], RFD_CMD_EOL
  264.     mov SI, ES:[SI+rfd_next]
  265.     mov c507_&name&_data.c507_cur_frame, SI
  266.  
  267.     mov SI, c507_&name&_data.c507_last_rfd
  268.     mov ES:[SI+rfd_cmd], 0
  269.  
  270.     mov c507_&name&_data.c507_last_rfd, AX
  271.  
  272.     mov AX, ES:[SCB+scb_status]         ;; is the reciever still recieving?
  273.     and AX, SCB_STAT_RUS_MSK
  274.     cmp AX, SCB_STAT_RUS_READY
  275.     jz no_restart
  276.         mov SI, c507_&name&_data.c507_cur_frame
  277.     mov AX, 16        ;; only look forward 16 packets at most
  278.         look_first_ndone:
  279.             test ES:[SI+rfd_status], RFD_STAT_DONE
  280.             jz found_restart
  281.  
  282.             mov SI, ES:[SI+rfd_next]
  283.         dec AX
  284.         jnz look_first_ndone
  285.         found_restart:
  286.         mov ES:[SCB+scb_rframes], SI
  287.         mov ES:[SI+rfd_status], 0
  288.         cmp word ptr ES:[SI+rfd_rbd], 0FFFFH
  289.         jnz ok_rbd
  290.             mov SI, c507_&name&_data.c507_last_rfd
  291.             mov AX, ES:[SI+rfd_rbd]
  292.             mov SI, ES:[SCB+scb_rframes]
  293.             mov ES:[SI+rfd_rbd], AX
  294.         ok_rbd:
  295.     
  296.         mov ES:[SCB+scb_cmd], SCB_RUC_START
  297.             ;; signal the 82586
  298.         WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES c507_&name&_io, C507_IO_ATTN
  299.     no_restart:
  300.  
  301.     mov SI, DX                                  ;; restore SI
  302.     mov AX, ES
  303.     xchg AX, c507_&name&_data.c507_base         ;; restore ES
  304.     mov ES, AX
  305. ENDM
  306.  
  307.  
  308. ;;******************************************************************************
  309. ;;   C507_IF_R_CONT_in_BX_CX_ES name, ok
  310. ;;       IF_R_CONT determines if the packet returned by R_READ in BX:ES
  311. ;;       of length CX is continuous.  If it is it jumps to 'ok' otherwise
  312. ;;       it just returns
  313. ;;
  314. C507_IF_R_CONT_in_BX_CX_ES_const_BX_CX_DX_BP_SI_DI_ES MACRO name, ok
  315.     .errb <ok>
  316.  
  317.     mov AX, BX
  318.     add AX, CX
  319.     cmp AX, c507_&name&_data.c507_end_buff
  320.     jb ok
  321. ENDM
  322.  
  323.  
  324. ;;******************************************************************************
  325. ;;   IF_W_ACCESS_in_CX_out_DI_ES name, no_buffer
  326. ;;       IF_W_ACCESS returns a pointer to an output buffer for a packet.  The 
  327. ;;       pointer is returned in DI:ES.  If the ouptut buffer is busy, this 
  328. ;;       routine will jump to 'no_buffer'.  The output buffer  min(CX, 1536) 
  329. ;;       bytes long
  330. ;;
  331. C507_IF_W_ACCESS_in_CX_out_DI_ES_const_BX_CX_BP MACRO name, no_buffer
  332.     local wait_busy, buffer_free, com_accepted, wait_com_accept, nocarry
  333.     .errb <no_buffer>
  334.  
  335.         ;; we ignore CX and always return a buffer 1536 bytes long
  336.  
  337.     mov ES, c507_&name&_data.c507_base
  338.     mov SI, c507_&name&_data.c507_cur_tcb
  339.  
  340.     cmp ES:[SI+cu_status], 0            ;; has the RU done ANYTHING with stat
  341.     jnz com_accepted
  342.                 ;; it may be 0 if the CU hasn't even accepted the command
  343.                 ;; check for this and wait if necessary
  344.         xor DX, DX                      ;; so we don't loop forever
  345.         wait_com_accept:
  346.             test ES:[SCB+scb_cmd], SCB_CMD_CUC_MSK
  347.             jz com_accepted
  348.             dec DX
  349.         jnz wait_com_accept
  350.     com_accepted:
  351.  
  352.     xor DX, DX                  ;; so we don't loop forever
  353.     wait_busy:
  354.         test ES:[SI+cu_status], CU_STAT_BUSY
  355.         jz buffer_free
  356.         dec DX
  357.     jnz wait_busy
  358.     buffer_free:
  359.  
  360.     mov SI, ES:[SI+cu_params+trans_tbd]
  361.     mov DI, ES:[SI+tbd_buff.offs]
  362. ENDM
  363.  
  364.  
  365. ;;******************************************************************************
  366. ;;   IF_W_WRITE_in_CX name
  367. ;;       IF_W_WRITE actually signals the ethernet board to write a packet to 
  368. ;;       the ethernet.  The packet is assumed to be in the buffer returned by 
  369. ;;       IF_W_ACCESS. CX is the length of the packet to send.  
  370. ;;
  371. C507_IF_W_WRITE_in_CX_const_BX_BP_ES MACRO name
  372.     local not_tcmd1, check_prev_com, no_prev_com, wait_busy, buffer_free
  373.     .errb <name>
  374.  
  375.     mov DX, ES                                  ;; save ES
  376.     mov ES, c507_&name&_data.c507_base
  377.     mov DI, c507_&name&_data.c507_cur_tcb
  378.  
  379.         ;; make any previous command has been recognized before
  380.         ;; sending this next one.
  381.     xor AX, AX
  382.     check_prev_com:
  383.         test ES:[SCB+scb_cmd], SCB_CMD_CUC_MSK
  384.         jz no_prev_com
  385.         dec AX
  386.     jnz check_prev_com
  387.     no_prev_com:
  388.  
  389.     xor AX, AX
  390.     wait_busy:
  391.         test ES:[DI+cu_status], CU_STAT_BUSY
  392.         jz buffer_free
  393.         dec AX
  394.     jnz wait_busy
  395.     buffer_free:
  396.  
  397.     mov ES:[DI+cu_status], 0
  398.     mov ES:[DI+cu_cmd], CU_CMD_EOL+CU_CMD_TRANS ;; probably unnecessary
  399.     mov ES:[DI+cu_params+trans_len], CX         ;; probably unnecessary
  400.     mov SI, ES:[DI+cu_params+trans_tbd]
  401.     add CX, TBD_LEN_EOL
  402.     mov ES:[SI+tbd_len], CX
  403.  
  404.         ;; send our transmit command
  405.     mov SI, offset SCB
  406.     mov ES:[SI+scb_status], 0
  407.     mov ES:[SI+scb_cuc], DI
  408.     mov ES:[SI+scb_cmd], SCB_CUC_START
  409.     WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES c507_&name&_io, C507_IO_ATTN
  410.  
  411.         ;; update the tcb pointer to the 'other' command block
  412.     mov AX, CU_TCMD1
  413.     cmp AX, DI
  414.     jnz not_tcmd1
  415.         mov AX, CU_TCMD2
  416.     not_tcmd1:
  417.     mov c507_&name&_data.c507_cur_tcb, AX
  418.  
  419.     mov ES, DX                                  ;; restore ES
  420. ENDM
  421.  
  422.  
  423. ;;******************************************************************************
  424. ;;   IF_SET_ADDRESS_in_SI name
  425. ;;       IF_SET_ADDRESS_in_SI sets the hardware address to be the value
  426. ;;       pointed to by SI.  Note this function may be a no-op if the
  427. ;;       hardware address cannot be set (ETHERNET for example)
  428. ;;
  429.  
  430. C507_IF_SET_ADDRESS_in_SI_const_BX_CX_BP_DI_ES MACRO name
  431.     .err    ;; we don't support setting ethernet addresses (yet)
  432.     ENDM
  433.  
  434.  
  435. ;;******************************************************************************
  436. ;;   IF_COPY_in_CX_SI_DI_ES_out_SI_DI name
  437. ;;      IF_COPY_in_CX_SI_DI_ES copys a packet from the input buffer (pointed 
  438. ;;      to by SI and the segement register given in IF_DECLARE) to an output 
  439. ;;      buffer (pointed to by DI and dest_reg) of length CX.   It assumes the
  440. ;;      output buffer is contiguous.  (and the caller shouln't care if the 
  441. ;;      input buffer is contiguous)
  442. ;;
  443. C507_IF_COPY_in_CX_SI_DI_ES_out_SI_DI_const_BX_BP_ES MACRO name
  444.     local wrap, done
  445.     .errb <name>
  446.  
  447.     mov DX, DS                                  ;; save DS
  448.     mov AX, c507_&name&_data.c507_end_buff
  449.     sub AX, SI                                  ;; space till end
  450.     cmp AX, CX
  451.     jbe wrap
  452.                 inc CX
  453.                 shr CX, 1
  454.                 mov DS, c507_&name&_data.c507_base
  455.                 rep movsw
  456.                 jmp done
  457.                 
  458.     wrap:
  459.                 xchg AX, CX
  460.                 sub AX, CX
  461.  
  462.                 mov DS, c507_&name&_data.c507_base
  463.                 inc CX
  464.                 shr CX, 1
  465.                 rep movsw
  466.  
  467.                 mov CX, AX
  468.                 mov DS, DX
  469.                         ;; remember this instruction rely on DS
  470.                         mov SI, c507_&name&_data.c507_start_buff
  471.                 mov DS, c507_&name&_data.c507_base
  472.                 inc CX
  473.                 shr CX, 1
  474.                 rep movsw
  475.  
  476.    done:
  477.    mov DS, DX                                   ;; restore DS
  478. ENDM
  479.  
  480.  
  481. ;;******************************************************************************
  482. ;; These macros and definitions are specific to the 3C507
  483.  
  484. C507_ID_PORT = 100H
  485.  
  486. C507_IO_ADDR            = 00H
  487. C507_IO_CTR             = 06H
  488. C507_IO_INT_CLEAR       = 0AH
  489. C507_IO_ATTN            = 0BH
  490. C507_IO_ROM             = 0DH
  491. C507_IO_RAM             = 0EH
  492. C507_IO_INT             = 0FH
  493.  
  494.         ;; values for teh IO_CTR reg
  495. C507_CTR_RUN            = 080H          ;; 1 = run 0 = reset
  496. C507_CTR_CA             = 040H          ;; obsolete way of to a chan attn
  497. C507_CTR_LOOP           = 020H          ;; put in loopback
  498. C507_CTR_LAD            = 010H          ;; LA address decode disable
  499. C507_CTR_INT            = 008H          ;; interupt is pending (read only)
  500. C507_CTR_IEN            = 004H          ;; interupt enable
  501. C507_CTR_PG_MSK         = 003H          ;; controls first 6 locations
  502.  
  503.         ;; values for the CTR_PG field
  504. C507_PG_3COM            = 00H           ;; page that has '*3com*' in it
  505. C507_PG_ETHER           = 01H           ;; page ethernet address in it
  506.  
  507.  
  508. ;;*******************************************************************
  509. ;; This macro sends the ID sequence that the 3Com 3C507 responds to.
  510. ;; to the I/O address 'port'.
  511.  
  512. C507_SEND_ID_const_BX_BP_SI_DI_ES MACRO port
  513.     local id_loop, no_xor
  514.  
  515.     mov CX, 0FFH
  516.     mov AL, 0FFH
  517.     id_loop:
  518.         WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES port, 0
  519.         shl AL, 1
  520.         jnc no_xor
  521.             xor AL, 0E7H
  522.         no_xor:
  523.     loop id_loop
  524.  
  525. ENDM
  526.  
  527. ;;*****************************************************************
  528. ;; this routine gets the ethernet address from the 3Com I/O registers
  529. ;; and places it in the buffer pointed to by SI
  530. C507_GET_ADDRESS_in_SI_const_BX_BP_DI_ES MACRO port
  531.     local eaddr_loop
  532.  
  533.         ;; get the ethernet address
  534.      mov AL, C507_CTR_RUN+C507_PG_ETHER
  535.      WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES port, C507_IO_CTR
  536.      mov CX, 6
  537.      mov DX, port+C507_IO_ADDR
  538.      eaddr_loop:
  539.         in AL, DX
  540.         mov [SI], AL
  541.         inc DX
  542.         inc SI
  543.      loop eaddr_loop
  544. ENDM
  545.  
  546.  
  547. ;;********************************************************************
  548. ;; These definitions have more to do with the 82586
  549.  
  550. longptr struc           ;; just allows me to get at 8086 long ptrs easily
  551.     offs dw ?
  552.     segm dw ?
  553. longptr ends
  554.  
  555. ;;*********************************************************************
  556.  
  557.         ;; This structure is always at a fixed location, and points to
  558.         ;; the system control pointer
  559. i82586_root struc                       ;; the root pointer
  560.     root_bus    dw 0
  561.     root_zero   db 4 dup (0)
  562.     root_scp    dd ?
  563. i82586_root ends
  564.  
  565. I82586_FIXED_ROOT       = 0FFF6H        ;; this is the fixed position 
  566.  
  567. ;;*********************************************************************
  568.  
  569.         ;; The system control pointer, in turn, points to the
  570.         ;; system control block
  571. i82586_scp struc                        ;; the system control pointer
  572.     scp_busy    dw 0                    ;; 82586 sets to 0 when reset complete
  573.     scp_scb     dw 0                    ;; offset to system control block
  574.     scp_base    dd 0                    ;; base for all 16 bit pointers
  575. i82586_scp ends                         ;; the system control block
  576.  
  577.  
  578. ;;*********************************************************************
  579.  
  580.         ;; The system control block is the heart of the communication
  581.         ;; between the CPU and the 82586.   The 82586 has a control
  582.         ;; unit (CU) which you can issue commands to, and a recieve
  583.         ;; unit (RU) that buffers packets.  Commands to these units
  584.         ;; are given from this structure.
  585. i82586_scb struc                        ;; the system control block
  586.     scb_status    dw 0                  ;; RU and CU status
  587.     scb_cmd       dw 0                  ;; RU and/or CU command
  588.     scb_cuc       dw 0                  ;; CU command (list)
  589.     scb_rframes   dw 0                  ;; buffers for RU
  590.     scb_crc_errs  dw 0                  ;; CRC error count
  591.     scb_aln_errs  dw 0                  ;; Alignment error count
  592.     scb_rcs_errs  dw 0                  ;; Resource error (queue filled)
  593.     scb_ovrn_errs dw 0                  ;; Overruns (memory busy)
  594. i82586_scb ends
  595.  
  596.         ;; masks for the scb_status field
  597. SCB_STAT_CX       = 08000H              ;; command with interupt executed
  598. SCB_STAT_FR       = 04000H              ;; Frame recieved
  599. SCB_STAT_CNR      = 02000H              ;; command unit left active state
  600. SCB_STAT_RNR      = 01000H              ;; receive unit left active state
  601. SCB_STAT_CUS_MSK  = 00700H              ;; command status mask
  602. SCB_STAT_RUS_MSK  = 00070H              ;; reciever status mask
  603.  
  604.         ;; these are the values for teh RUS_MSK field
  605. SCB_STAT_RUS_IDLE  = 00000H             ;; reciever idle
  606. SCB_STAT_RUS_SUSP  = 00010H             ;; reciever suspended
  607. SCB_STAT_RUS_NORES = 00020H             ;; reciever no_resources
  608. SCB_STAT_RUS_READY = 00040H             ;; reciever ready
  609.  
  610.         ;; masks for the scb_cmd (set by CPU cleared by 82586)
  611. SCB_CMD_ACK_CX    = 08000H              ;; acks command executed
  612. SCB_CMD_ACK_FR    = 04000H              ;; acks frame received
  613. SCB_CMD_ACK_CNA   = 02000H              ;; acks CU not ready
  614. SCB_CMD_ACK_RNR   = 01000H              ;; acks RU not ready
  615. SCB_CMD_CUC_MSK   = 00700H              ;; CU command mask 
  616. SCB_CMD_RST       = 00080H              ;; reset the 82586 
  617. SCB_CMD_RUC_MSK   = 00070H              ;; RU command mask
  618.  
  619.         ;; values for the CUC_MSK part of the scb_cmd field
  620. SCB_CUC_START     = 00100H              ;; start a CU command
  621. SCB_CUC_RESUME    = 00200H
  622. SCB_CUC_SUSPEND   = 00300H
  623. SCB_CUC_ABORT     = 00400H
  624.  
  625.         ;; values for the RUC_MSK part of the scb_cmd field
  626. SCB_RUC_START     = 00010H              ;; start RU receiving packets
  627. SCB_RUC_RESUME    = 00020H
  628. SCB_RUC_SUSPEND   = 00030H
  629. SCB_RUC_ABORT     = 00040H
  630.  
  631.  
  632. ;;*********************************************************************
  633.  
  634.         ;; the scb_cuc points to a list of commands for the CU
  635.         ;; to execute.  Each entry in the list has this format
  636. i82586_cu struc
  637.     cu_status    dw 0                   ;; status of this command
  638.     cu_cmd       dw 0                   ;; specifies the op
  639.     cu_next      dw 0                   ;; next cmd in the list
  640.     cu_params    db 58 dup (0)          ;; depends on particular cmd
  641. i82586_cu ends
  642.  
  643.         ;; values for the cu_status field
  644. CU_STAT_COMPLETE        = 08000H        ;; command is completed
  645. CU_STAT_BUSY            = 04000H        ;; command not complete
  646. CU_STAT_OK              = 02000H        ;; finished and OK
  647.  
  648.         ;; values for the cu_cmd field
  649. CU_CMD_CMD_MSK          = 00007H        ;; mask for the command
  650. CU_CMD_EOL              = 08000H        ;; last command list in list
  651. CU_CMD_SUSPEND          = 04000H        ;; suspend after completion
  652. CU_CMD_INT              = 02000H        ;; interupt after completion
  653.  
  654.  
  655.         ;; values for the CMD_MSK parat of the cu_cmd field
  656. CU_CMD_NOOP             = 0             ;; noop command
  657. CU_CMD_ADDRESS_SET      = 1             ;; set ethernet address
  658. CU_CMD_CONFIG           = 2             ;; configure ethernet params
  659. CU_CMD_MULTI_SET        = 3             ;; set multicast addresses
  660. CU_CMD_TRANS            = 4             ;; transmit packet
  661. CU_CMD_TDR              = 5             ;; Time domain reflectometer
  662. CU_CMD_DUMP             = 6             ;; dump internal state 
  663. CU_CMD_DIAGNOSE         = 7             ;; run diagnostics
  664.  
  665. ;;*******************************************************************
  666.  
  667.         ;; these are the parameters of the TRAMSMIT command
  668. i82586_trans struc                      
  669.     trans_tbd      dw 0                 ;; points to buffer descriptor
  670.     trans_dst_addr db 6 dup (0)         ;; address to send it to (not used)
  671.     trans_len      dw 0                 ;; 802.3 length field (not used)
  672. i82586_trans ends
  673.  
  674.         ;; the first parameter of a transmit command points to a list 
  675.         ;; of transmit buffer discriptors that characterize the 
  676.         ;; packet to send
  677. i82586_tbd struc                        
  678.     tbd_len     dw 0                    ;; length and EOL flag
  679.     tbd_next    dw 0                    ;; pointer to next descriptor
  680.     tbd_buff    dd 0                    ;; a long pointer to the buffer
  681. i82586_tbd ends
  682.  
  683.         ;; the bit fields bit in the tbd_len field
  684. TBD_LEN_EOL             = 08000H        ;; Last buff in list
  685. TBD_LEN_LEN_MSK         = 03FFFH        ;; this part is the length
  686.  
  687.  
  688. ;;*******************************************************************
  689.  
  690.         ;; the scb_rfd field points to a list of frame descriptors.
  691.         ;; each of these describe a single packet
  692. i82586_rfd struc                        
  693.     rfd_status          dw 0            ;; recieve status
  694.     rfd_cmd             dw 0            ;; really just specifies EOL
  695.     rfd_next            dw 0            ;; next frame descriptor
  696.     rfd_rbd             dw 0            ;; pointer to buff descriptor
  697.     rfd_dst_addr        db 6 dup (0)    ;; ethernet address of destination
  698.     rfd_src_addr        db 6 dup (0)    ;; ethernet address of source
  699.     rfd_len             dw 0            ;; length of packet
  700. i82586_rfd ends                 
  701.  
  702. RFD_STAT_DONE     = 08000H
  703. RFD_STAT_CONSUMED = 04000H
  704. RFD_STAT_OK       = 02000H      
  705. RFD_STAT_CRC      = 00800H
  706. RFD_STAT_ALN      = 00400H
  707. RFD_STAT_RSC      = 00200H
  708. RFD_STAT_OVRN     = 00100H
  709. RFD_STAT_RUNT     = 00080H
  710.  
  711. RFD_CMD_EOL     = 08000H                ;; End of frame list 
  712.         
  713.         ;; the rdb_buff field points to a buffer descriptor, which is
  714.         ;; a unit of memory allocation.
  715. i82586_rbd struc                        
  716.     rbd_used_len        dw 0            ;; also hold some flag bits
  717.     rbd_next            dw 0            ;; next buffer descriptor
  718.     rbd_buff            dd 0            ;; pointer to actual memory
  719.     rbd_len             dw 0            ;; length of buffer
  720. i82586_rbd ends                 
  721.         
  722.         ;; masks for the rdb_used_len field     
  723. RBD_USED_LEN_EOF        = 08000H        ;; Last buff in a frame list
  724. RBD_USED_LEN_VALID      = 04000H        ;; says the used_len field valid
  725. RBD_USED_LEN_MSK        = 03FFFH        ;; this part is the used length
  726.  
  727. RBD_LEN_MSK     = 03FFFH                ;; this part is the used length
  728. RBD_LEN_EOL     = 08000H                ;; End of buffer list 
  729.  
  730.  
  731.  
  732. ;;***********************************************************************
  733. ;; setup the chain of recieve buffers.  SI points to a block
  734. ;; of memory  'len'*(SIZE i82586_rfd) bytes long.  Note 1 < CX < 16K
  735.  
  736. C507_SETUP_R_FRAMES_in_CX_SI_ES_const_AX_BP_ES MACRO 
  737.     local init_loop
  738.  
  739.         ;; create a circular list of receive buffers
  740.     mov DX, SI                          ;; save original pointer
  741.     mov DI, SI
  742.     add DI, (SIZE i82586_rfd)
  743.     dec CX
  744.     init_loop:
  745.                 ;; set up a frame descriptor
  746.         mov ES:[SI+rfd_status], 0
  747.         mov ES:[SI+rfd_cmd], 0          ;; says NOT end of list
  748.         mov ES:[SI+rfd_next], DI
  749.         mov ES:[SI+rfd_rbd], 0FFFFH
  750.  
  751.         add SI, (SIZE i82586_rfd)
  752.         add DI, (SIZE i82586_rfd)
  753.         dec CX
  754.     jnz init_loop
  755.  
  756.     mov ES:[SI+rfd_cmd], RFD_CMD_EOL    ;; logical end of list
  757.     mov ES:[SI+rfd_next], DX            ;; close the loop
  758.     mov ES:[SI+rfd_rbd], 0FFFFH
  759. ENDM
  760.  
  761.  
  762. ;;***********************************************************************
  763. ;; setup the chain of recieve buffers.  BX points to the begining of
  764. ;; a block of memory 'len'* CX bytes long and SI points to a block
  765. ;; of memory  'len'*(SIZE i82586_rbd) bytes long.  Note 1 < CX < 16K
  766. ;; it returns in SI the start of the list of buffer descriptors.
  767.  
  768. C507_SETUP_R_BUFFS_in_BX_CX_SI_ES_out_SI_const_AX_BP_ES MACRO len
  769.     local init_loop
  770.  
  771.         ;; create a circular list of receive buffers
  772.     mov DX, SI                          ;; save original pointer
  773.     mov DI, SI
  774.     add DI, (SIZE i82586_rbd)
  775.     dec CX
  776.     init_loop:
  777.                 ;; set up a buffer descriptor
  778.         mov ES:[SI+rbd_next], DI
  779.         mov ES:[SI+rbd_buff.offs], BX
  780.         mov ES:[SI+rbd_buff.segm], 0
  781.         mov ES:[SI+rbd_len], len
  782.  
  783.         add SI, (SIZE i82586_rbd)
  784.         add DI, (SIZE i82586_rbd)
  785.         add BX, len
  786.         dec CX
  787.     jnz init_loop
  788.  
  789.     mov ES:[SI+rbd_next], DX            ;; close the loop
  790.     mov ES:[SI+rbd_buff.offs], BX
  791.     mov ES:[SI+rbd_buff.segm], 0
  792.     mov ES:[SI+rbd_len], len+RBD_LEN_EOL          ;; logical end of list
  793.  
  794.     mov SI, DX                          ;; return the first one
  795. ENDM
  796.  
  797.  
  798.  
  799. ;;***********************************************************************
  800. ;; setup the data structure needed for the receiver.  CX, ES:SI is the
  801. ;; len and begining of shared memory in which to set it up.  It returns
  802. ;; in SI the pointer that belongs in the scb_rframes field of the system
  803. ;; control block 'len' is the length of a buffer 
  804.  
  805. C507_SETUP_R_MEM_in_CX_SI_ES_out_SI_const_ES MACRO len
  806.  
  807.     ;; since we allocate two buffers for every frame 
  808. TOTAL_BUFF_LEN = len + (SIZE i82586_rbd) + (SIZE i82586_rfd)
  809.  
  810.    mov AX, CX
  811.    sub AX, (SIZE i82586_rfd)    ;; Want an extra frame desc
  812.    xor DX, DX
  813.    mov BX, TOTAL_BUFF_LEN
  814.    div BX
  815.  
  816.    mov CX, AX                   ;; AX holds the number of buffers
  817.    mov BX, SI                   ;; BX start of buffer space
  818.    mov DX, len
  819.    mul DX
  820.    add SI, AX                   ;; SI start of buff desc
  821.  
  822.    mov BP, SI
  823.    mov AX, CX
  824.    mov DX, (SIZE i82586_rbd)
  825.    mul DX
  826.    add BP, AX                   ;; BP points to the start of frame desc
  827.  
  828.    mov AX, CX                   ;; CX holds the number of buffers
  829.    inc AX                       ;; AX holds the number of frames
  830.  
  831.    C507_SETUP_R_BUFFS_in_BX_CX_SI_ES_out_SI_const_AX_BP_ES len
  832.  
  833.    mov CX, AX
  834.    mov AX, SI                   ;; save pointer to start of buffer list
  835.    mov SI, BP
  836.    C507_SETUP_R_FRAMES_in_CX_SI_ES_const_AX_BP_ES 
  837.  
  838.    mov SI, BP                   ;; return final pointer to frames
  839.    mov ES:[SI+rfd_rbd], AX      ;; link the frames to the buffs
  840. ENDM
  841.  
  842.  
  843. ;;***********************************************************************
  844. ;; setup the data structures needed to communicate with the 82586.
  845. ;; SI:ES points to the shared memory window.  Note that We only use
  846. ;; the memory ABOVE SI in the ES segment, thus if SI=C000 there is
  847. ;; a 4K window.   In addition, some data structures are in 'standard'
  848. ;; positions that can be used directly.
  849. ;; 
  850.  
  851. SCP             = 0FFE0H        ;; place for system control ptr
  852. SCB             = (SCP-16)      ;; place for system control block
  853. CU_GCMD         = (SCB-32)      ;; generic command (32 bytes long)
  854. CU_TCMD1        = (CU_GCMD-32)  ;; first trans command (32 bytes long)
  855. CU_TCMD2        = (CU_TCMD1-32) ;; second trans command (32 bytes long)
  856. CU_TBD1         = (CU_TCMD2-8)  ;; first Transmit buffer descriptor
  857. CU_TBD2         = (CU_TBD1-8)   ;; second Transmit buffer descriptor
  858. CU_TB1          = (CU_TBD2-1536);; first Trans buffer (1536 bytes long)
  859. CU_TB2          = (CU_TB1-1536) ;; second Trans buffer (1536 bytes long)
  860.  
  861. START_RESERVED  = CU_TB2        ;; start of fixed allocated memory
  862. LEN_R_BUFF      = 256           ;; this is a optimization param
  863.  
  864.  
  865. ;;*************************************************************************
  866. ;; SETUP_MEM sets up all the shared memory data structures that the 82586
  867. ;; uses SI:ES points the the begining of the memory.  It is assumed that
  868. ;; the memory ranges is ES:SI to ES:FFFF 
  869. ;;
  870. C507_SETUP_MEM_in_SI_ES_const_ES MACRO
  871.  
  872.     mov DI, SI                  ;; zero out memory, it makes reading
  873.     xor AX, AX                  ;; dumps easier
  874.     mov DX, SI
  875.     shr DX, 1
  876.     mov CX, 8000H
  877.     sub CX, DX
  878.     rep stosw
  879.  
  880.         ;; setup ROOT
  881.     mov BX, offset I82586_FIXED_ROOT
  882.     mov ES:[BX+root_bus], 0
  883.     mov ES:[BX+root_scp.offs], offset SCP
  884.     mov ES:[BX+root_scp.segm], 0
  885.  
  886.         ;; setup SCP
  887.     mov BX, offset SCP
  888.     mov ES:[BX+scp_busy], 1             ;; set the busy bit
  889.     mov ES:[BX+scp_scb], SCB
  890.     mov ES:[BX+scp_base.offs], 0
  891.     mov ES:[BX+scp_base.segm], 0
  892.  
  893.         ;; setup SCB
  894.     mov BX, offset SCB
  895.     mov ES:[BX+scb_cmd], 0
  896.     mov ES:[BX+scb_status], 0
  897.     mov ES:[BX+scb_crc_errs], 0
  898.     mov ES:[BX+scb_aln_errs], 0
  899.     mov ES:[BX+scb_rcs_errs], 0
  900.     mov ES:[BX+scb_ovrn_errs], 0
  901.     mov ES:[BX+scb_cuc], offset CU_GCMD
  902.  
  903.         ;; get the length of the rest of memory
  904.     mov CX, START_RESERVED
  905.     sub CX, SI 
  906.     C507_SETUP_R_MEM_in_CX_SI_ES_out_SI_const_ES LEN_R_BUFF
  907.  
  908.     mov BX, offset SCB
  909.     mov ES:[BX+scb_rframes], SI
  910.  
  911.         ;; setup transmit buffers descriptors
  912.     mov BX, CU_TCMD1
  913.     mov ES:[BX+cu_cmd], CU_CMD_EOL+CU_CMD_TRANS
  914.     mov ES:[BX+cu_params+trans_tbd], CU_TBD1
  915.  
  916.     mov BX, CU_TCMD2
  917.     mov ES:[BX+cu_cmd], CU_CMD_EOL+CU_CMD_TRANS
  918.     mov ES:[BX+cu_params+trans_tbd], CU_TBD2
  919.  
  920.     mov BX, CU_TBD1
  921.     mov ES:[BX+tbd_buff.offs], offset CU_TB1
  922.     mov ES:[BX+tbd_buff.segm], 0
  923.  
  924.     mov BX, CU_TBD2
  925.     mov ES:[BX+tbd_buff.offs], offset CU_TB2
  926.     mov ES:[BX+tbd_buff.segm], 0
  927.  
  928. ENDM
  929.  
  930.  
  931. ;;***********************************************************************
  932. ;; DO_CMD simply executes the command 'command'.  It assumes that all
  933. ;; parameters to the command have been set up in the DO_CMD_PARAMS
  934. ;; structure below.  This command waits for completion and jumps to
  935. ;; 'fail' if unsuccessful.  (note that DO_CMD_PARAMS points to the
  936. ;; command specific part of the command.
  937. ;; Note also that this command should not be used if it is possible
  938. ;; that other commands are in progress
  939.  
  940. DO_CMD_PARAMS = (CU_GCMD+6)             
  941.  
  942. C507_DO_CMD_in_ES_const_BP_SI_DI_ES MACRO command, port, fail
  943.     local waitloop, done
  944.     .errb <fail>
  945.  
  946.     mov BX, offset SCB
  947.     mov ES:[BX+scb_status], 0
  948.     mov ES:[BX+scb_cuc], offset CU_GCMD
  949.     mov ES:[BX+scb_cmd], SCB_CUC_START
  950.  
  951.     mov BX, offset CU_GCMD
  952.     mov ES:[BX+cu_status], 0
  953.     mov ES:[BX+cu_cmd], CU_CMD_EOL+command
  954.         ;; we assume that the rest of the command is set up
  955.  
  956.         ;; signal the 82586
  957.     WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES port, C507_IO_ATTN
  958.  
  959.     xor CX, CX                  ;; don't wait forever
  960.     waitloop:
  961.         dec CX
  962.         jz fail
  963.  
  964.         mov AX, ES:[BX+cu_status]
  965.         test AX, CU_STAT_COMPLETE
  966.     jz waitloop                 ;; wait for completion
  967.     test AX, CU_STAT_OK
  968.     jz fail     
  969.  
  970. ENDM
  971.     
  972.  
  973. ;;***********************************************************************
  974. ;; do the intial setup of the 3C507 card
  975.  
  976. C507_RESET_82586_in_ES MACRO port, fail
  977.    local reset_wait, reset_done, reset_loop
  978.  
  979.         ;; reset the 82586
  980.     mov ES:[SCP+scp_busy], 1            ;; set the busy bit
  981.  
  982.     mov AL, 0  
  983.     WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES port, C507_IO_CTR
  984.     nop         ;; wait 10 clock cycles
  985.     nop
  986.  
  987.         ;; just in case there was an interupt pending, clear it
  988.     WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES port, C507_IO_INT_CLEAR
  989.  
  990.     mov AL, C507_CTR_RUN+C507_PG_ETHER 
  991.     WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES port, C507_IO_CTR
  992.     nop
  993.     nop
  994.  
  995.     WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES port, C507_IO_ATTN
  996.  
  997.     mov CX, 256
  998.     reset_loop:
  999.         cmp ES:[SCP+scp_busy], 0
  1000.         jz reset_done
  1001.     loop reset_loop
  1002.     jmp fail
  1003.  
  1004.     reset_done:
  1005. ENDM
  1006.  
  1007.  
  1008. ;;***********************************************************************
  1009. ;; do the intial setup of the 3C507 card
  1010.  
  1011. C507_INIT_SETUP_out_ES MACRO port, segment, len, addr, promiscuous, fail
  1012.    local eaddr_loop, done, diag_fail, config_fail, setaddr_fail
  1013.    local reset_fail, ru_on_fail, wait_ru_on, done_wait_ru
  1014.    .errb <len>
  1015.  
  1016.         ;; adjust ES so that ES:SI point to begining and ES:FFFF the end
  1017.     mov AX, segment
  1018.     if ((len/16) ne 0)    ;; This is a kludge because the assembler wraps 10000H
  1019.     sub AX, (1000H - (len / 16))
  1020.     endif
  1021.     mov ES, AX
  1022.     mov SI, 10000H - len
  1023.  
  1024.         ;; test the memory just a bit
  1025.     mov ES:[SI], 5F75H
  1026.     mov DX, ES:[SI]
  1027.     mov AX, 0101H               ;; signals a memory check error type 1
  1028.     cmp DX, 5F75H
  1029.     jnz fail
  1030.  
  1031.     mov ES:[0FFFEH], 57A5H
  1032.     mov DX, ES:[0FFFEH]
  1033.     mov AX, 0102H               ;; signals a memory check error type 2
  1034.     cmp DX, 57A5H
  1035.     jnz fail
  1036.  
  1037.     C507_SETUP_MEM_in_SI_ES_const_ES 
  1038.  
  1039.  
  1040.         ;; just to test the board is there, get the first char
  1041.         ;; of the '*3com*' identifier from the I/O ROM.  
  1042.     mov AL, C507_CTR_RUN+C507_PG_3COM  
  1043.     WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES port, C507_IO_CTR
  1044.     READ_PORT_out_AL_const_BX_CX_BP_SI_DI_ES port, C507_IO_ADDR
  1045.     mov DL, AL
  1046.     mov AX, 0201H               ;; signals 82586 not there
  1047.     cmp DL, '*'                 ;; should be part of *3com*' string
  1048.     jnz fail
  1049.  
  1050.     C507_RESET_82586_in_ES port reset_fail
  1051.  
  1052.         ;; check the setup by doing a diag
  1053.     C507_DO_CMD_in_ES_const_BP_SI_DI_ES CU_CMD_DIAGNOSE, port, diag_fail
  1054.  
  1055.         ;; configure ethernet params
  1056.     mov BX, offset DO_CMD_PARAMS 
  1057.     mov word ptr ES:[BX+0], 0080CH  ; fifo=8  byte count=12
  1058.     mov word ptr ES:[BX+2], 02E00H  ; preamble=4, add_len=6, DONT ins headers
  1059.     mov word ptr ES:[BX+4], 06000H  ; interframe spacing = 60h
  1060.     mov word ptr ES:[BX+6], 0F200H  ; retry = 15, slot time = 200h
  1061.     if promiscuous eq 1
  1062.         mov word ptr ES:[BX+8], 1   ; flags bit 1 means promiscuous
  1063.     else
  1064.         mov word ptr ES:[BX+8], 0   ; flags bit 1 means promiscuous
  1065.     endif
  1066.     mov word ptr ES:[BX+10], 0003CH  ; minimum frame length = 60
  1067.     C507_DO_CMD_in_ES_const_BP_SI_DI_ES CU_CMD_CONFIG, port, config_fail
  1068.  
  1069.         ;; set the ethernet address
  1070.     mov DI, offset DO_CMD_PARAMS 
  1071.     mov SI, offset addr
  1072.     mov CX, 3
  1073.     rep movsw
  1074.     C507_DO_CMD_in_ES_const_BP_SI_DI_ES CU_CMD_ADDRESS_SET, port, setaddr_fail
  1075.  
  1076.     mov BX, offset SCB
  1077.     mov ES:[BX+scb_status], 0
  1078.     mov ES:[BX+scb_cmd], SCB_RUC_START
  1079.  
  1080.         ;; signal the 82586
  1081.     WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES port, C507_IO_ATTN
  1082.  
  1083.     xor CX, CX
  1084.     wait_ru_on:
  1085.         dec CX
  1086.         mov AX, ES:[BX+scb_status]
  1087.         and AX, SCB_STAT_RUS_MSK
  1088.         jnz done_wait_ru
  1089.         dec CX
  1090.     jnz wait_ru_on
  1091.     done_wait_ru:
  1092.     cmp AX, SCB_STAT_RUS_READY
  1093.     jz done
  1094.  
  1095. ru_on_fail:
  1096.     mov AX, 0206H               ;; failed to turn RU on
  1097.     jmp fail
  1098.  
  1099. reset_fail:
  1100.     mov AX, 0202H               ;; failed resetting the 82586
  1101.     jmp fail
  1102.  
  1103. diag_fail:
  1104.     mov AX, 0203H               ;; signals 82586 failed noop test
  1105.     jmp fail
  1106.  
  1107. config_fail:
  1108.     mov AX, 0204H               ;; signals 82586 failed config
  1109.     jmp fail
  1110.  
  1111. setaddr_fail:
  1112.     mov AX, 0205H               ;; signals 82586 failed set addr
  1113.     jmp fail
  1114.  
  1115.     done:
  1116. ENDM
  1117.  
  1118.  
  1119. ;;******************************************************************************
  1120. ;; utility functions needed only within this module
  1121.  
  1122. READ_PORT_out_AL_const_BX_CX_BP_SI_DI_ES MACRO port, if_io
  1123.     mov DX, if_io+port
  1124.     in  AL, DX                              ;; AL contains data read from port
  1125. ENDM
  1126.  
  1127. ;;******************************************************************************
  1128. WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES MACRO port, if_io
  1129.     mov DX, if_io+port
  1130.     out DX, AL                              ;; AL contains data read from port
  1131. ENDM 
  1132.  
  1133.